// 尝试使用libaudit的C API，但是玩不明白，所以直接使用auditctl命令
include!(concat!(env!("OUT_DIR"), "/audit_bindings.rs"));

pub struct AuditRs {}
impl AuditRs {
    pub fn new() -> Self {
        Self {}
    }
    /// 创建一个新的审计规则，监控指定文件，返回规则的key
    pub fn audit_new_rule(&self, file_path: String) -> anyhow::Result<String> {
        self.audit_new_rule_auditctl(file_path)
    }

    /// 将libaudit的C API使用bindgen绑定到Rust，然后在Rust中调用。玩不明白
    ///
    /// 已经能调通了，但是不知道怎么设置rule_key.以及file_path不生效。本质是重新实现了auditctl的功能，没有必要。
    ///
    /// include!(concat!(env!("OUT_DIR"), "/audit_bindings.rs"));
    // fn audit_new_rule_bindgen(&self, file_path: String) -> anyhow::Result<()> {
    //     unsafe {
    //         // 1. 打开 audit 连接
    //         let fd = audit_open();
    //         if fd < 0 {
    //             anyhow::bail!("Failed to open audit connection");
    //         }

    //         // 2. 创建审计规则，监控特定文件
    //         let rule = audit_rule_create_data();
    //         audit_rule_init_data(rule as *mut _);

    //         // 将文件路径转换为 C 字符串
    //         let c_file_path = CString::new(file_path)?;

    //         // 3. 添加监控目录规则
    //         let ret = audit_add_watch_dir(AUDIT_DIR as i32, rule as *mut _, c_file_path.as_ptr());
    //         if ret < 0 {
    //             audit_close(fd);
    //             anyhow::bail!("Failed to add audit rule watch");
    //         }

    //         // 4. 设置规则
    //         let ret = audit_add_rule_data(
    //             fd,
    //             rule as *mut _,
    //             AUDIT_FILTER_FS as i32,
    //             AUDIT_ALWAYS as i32,
    //         );
    //         if ret < 0 {
    //             println!("ret: {}", ret);
    //             audit_close(fd);
    //             anyhow::bail!("Failed to set audit rule");
    //         }
    //         println!("audit rule added successfully");
    //         // struct audit_reply reply;
    //         // audit_get_reply(fd, &reply, GET_REPLY_NONBLOCKING, 0);
    //         // 5. 关闭 audit 连接
    //         audit_close(fd);
    //     }

    //     Ok(())
    // }

    /// 直接使用auditctl命令添加审计规则
    /// 理由：auditctl本质是对libaudit的封装，使用auditctl命令更加简单。
    /// https://github.com/linux-audit/audit-userspace/blob/master/src/auditctl.c
    fn audit_new_rule_auditctl(&self, file_path: String) -> anyhow::Result<String> {
        // sudo auditctl -w {file_path} -F perm=wa -F pid!=$$ -F key=CM_{file_path}
        let rule_key = "CM_".to_owned() + &file_path;
        let pid = std::process::id();

        let output = std::process::Command::new("sudo")
            .arg("auditctl")
            .arg("-w")
            .arg(file_path)
            .arg("-F")
            .arg("perm=wa")
            .arg("-F")
            .arg(format!("pid!={}", pid))
            .arg("-F")
            .arg(format!("key={}", rule_key))
            .output()?;

        if !output.status.success() {
            println!("output: {:?}", output);
            anyhow::bail!("Failed to add audit rule");
        }
        Ok(rule_key.clone())
    }
}
